package com.example.quartz.utils;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

import java.util.Date;
import java.util.List;

import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

import com.example.quartz.dao.QrtzJobLogMapper;
import com.example.quartz.model.QrtzJobDetails;
import com.example.quartz.model.QrtzJobTriggers;
import com.example.quartz.utils.enums.TaskStatus;

/**
 * @Class QuartzManager
 * @Description 定时任务管理类
 * @Author xw
 * @Date 2017年3月31日17:24:07
 */
@Component
public class QuartzManager {

	private static final Logger LOG = LoggerFactory.getLogger(QuartzManager.class);

	@Autowired
	private Scheduler scheduler;

	@Autowired
	private QrtzJobLogMapper qrtzJobLogDao;

	private TransactionTemplate transactionTemplate;

	@Autowired
	public void setTransactionTemplate(PlatformTransactionManager transactionManager) {
		this.transactionTemplate = new TransactionTemplate(transactionManager);
	}

	/**
	 * @Title startup
	 * @Description 执行已启用的任务
	 * @Author xw
	 * @Date 2017年3月31日17:24:07
	 * @param jobDetail
	 * @throws Exception
	 */
	public void startup(QrtzJobDetails jobDetail) throws Exception {
		if (TaskStatus.ENABLE.name().equals(jobDetail.getJobStatus())) {
			Class<?> clazz = Class.forName(jobDetail.getQrtzTaskClazz());
			if (Job.class.isAssignableFrom(clazz)) {
				JobKey jobKey = JobKey.jobKey(jobDetail.getJobName(), jobDetail.getJobGroup());
				@SuppressWarnings("unchecked")
				JobDetail job = newJob((Class<? extends Job>) clazz).withIdentity(jobKey).build();
				job.getJobDataMap().put(TransactionJob.TRANSACTION_TEMPLATE, this.transactionTemplate);
				job.getJobDataMap().put(TransactionJob.JOB_LOG_DAO, this.qrtzJobLogDao);

				List<QrtzJobTriggers> jobTriggers =jobDetail.getJobTriggers(); //qrtzJobTriggersDao.selectByJobId(jobDetail.getId());
				TriggerKey triggerKey = null;
				CronTrigger trigger = null;
				Date ft = null;
				for (QrtzJobTriggers jobTrigger : jobTriggers) {
					if (TaskStatus.ENABLE.name().equals(jobTrigger.getTriggerStatus())) {
						triggerKey = TriggerKey.triggerKey(jobTrigger.getTriggerName(), jobTrigger.getTriggerGroup());
						// 调度未存在的触发器
						if (!scheduler.checkExists(triggerKey)) {
							TriggerBuilder<CronTrigger> triggerBuilder = newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule(jobTrigger.getCronExpression()));
							if (scheduler.checkExists(jobKey)) {
								// 任务已启用
								trigger = triggerBuilder.forJob(job).build();
								ft = scheduler.scheduleJob(trigger);
							} else {
								// 任务被停用
								trigger = triggerBuilder.build();
								ft = scheduler.scheduleJob(job, trigger);
							}

							LOG.info(jobKey + ":" + triggerKey + " startup scheduled to run at: " + ft + " and now is: " + new Date());
						}

					}
				}
			}
		}

	}

	/**
	 * @Title shutdown
	 * @Description 关闭已停用的任务
	 * @Author xw
	 * @Date 2017年3月31日17:24:07
	 * @param jobDetail
	 * @throws Exception
	 */
	public void shutdown(QrtzJobDetails jobDetail) throws Exception {
		if (TaskStatus.DISABLE.name().equals(jobDetail.getJobStatus())) {
			Class<?> clazz = Class.forName(jobDetail.getQrtzTaskClazz());
			if (Job.class.isAssignableFrom(clazz)) {
				JobKey jobKey = JobKey.jobKey(jobDetail.getJobName(), jobDetail.getJobGroup());
				if (scheduler.checkExists(jobKey)) {
					scheduler.deleteJob(jobKey);
					LOG.info(jobKey + " job shutdown scheduled and now is: " + new Date());
				}
			}
		}
	}

	/**
	 * @Title startup
	 * @Description 执行已启用的触发器，如果任务被停用则会启用任务
	 * @Author xw
	 * @Date 2017年3月31日17:24:07
	 * @param jobTriggers
	 * @throws Exception
	 */
	public void startup(QrtzJobTriggers jobTrigger) throws Exception {
		if (TaskStatus.ENABLE.name().equals(jobTrigger.getTriggerStatus())) {
			TriggerKey triggerKey = TriggerKey.triggerKey(jobTrigger.getTriggerName(), jobTrigger.getTriggerGroup());
			if (scheduler.checkExists(triggerKey)) {
				return;
			}
			TriggerBuilder<CronTrigger> triggerBuilder = newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule(jobTrigger.getCronExpression()));
			CronTrigger trigger = null;
			Date ft = null;

			QrtzJobDetails jobDetail = jobTrigger.getJobDetails();
			// 任务存在且处于启用状态
			Class<?> clazz = Class.forName(jobDetail.getQrtzTaskClazz());
			if (Job.class.isAssignableFrom(clazz)) {
				JobKey jobKey = JobKey.jobKey(jobDetail.getJobName(), jobDetail.getJobGroup());
				@SuppressWarnings("unchecked")
				JobDetail job = newJob((Class<? extends Job>) clazz).withIdentity(jobKey).build();
				job.getJobDataMap().put(TransactionJob.TRANSACTION_TEMPLATE, this.transactionTemplate);
				job.getJobDataMap().put(TransactionJob.JOB_LOG_DAO, this.qrtzJobLogDao);

				if (scheduler.checkExists(jobKey)) {
					// 任务已启用
					trigger = triggerBuilder.forJob(job).build();
					ft = scheduler.scheduleJob(trigger);
				} else {
					// 任务被停用
					trigger = triggerBuilder.build();
					ft = scheduler.scheduleJob(job, trigger);
				}
				LOG.info(jobKey + ":" + triggerKey + " startup scheduled to run at: " + ft + " and now is: " + new Date());
			}
		}

	}

	/**
	 * @Title shutdown
	 * @Description 关闭已停用的触发器
	 * @Author xw
	 * @Date 2017年3月31日17:24:07
	 * @param jobTriggers
	 * @throws Exception
	 */
	public void shutdown(QrtzJobTriggers jobTrigger) throws Exception {
		if (TaskStatus.DISABLE.name().equals(jobTrigger.getTriggerStatus())) {
			TriggerKey triggerKey = TriggerKey.triggerKey(jobTrigger.getTriggerName(), jobTrigger.getTriggerGroup());
			if (scheduler.checkExists(triggerKey)) {
				scheduler.unscheduleJob(triggerKey);
				LOG.info(triggerKey + " trigger shutdown scheduled and now is: " + new Date());
			}
		}
	}


}
